unit uImageDownloadThread;

interface
uses
  Classes,
  SysUtils,
  TypInfo,
  Variants,
  XMLDoc,
  DB,
  nxdb,
  ShoppingServiceXMLClasses,
  EbayConnect, uTypes,
  Forms, IdThread, IdSync, uThreadSync, IdComponent;

type

  TDownloadImagesThread =  class(TidThread)
  private
     // Private declarations
     FForm        : TForm;
     FOperationResult : AckCodeType;
     FErrorRecord   : eBayAPIError;
     FEItemId       : string;
     RecAdded       : Integer;
     FSyncObj       : TFTSync;
     FRxDelta       : Integer;
     FTxDelta       : Integer;
     FItemsToGet    : TStringList;
     FEbayShoppingConnect  : TEbayShoppingConnect;
     FGetMultipleItems     : TGetMultipleItems;
     FQuery       : TnxQuery;
     FQueryItems  : TnxQuery;
     FAppID       : string;
     FSiteID      : SiteCodeType;
     FGlobalID    : Global_ID;
     FUpdateRec   : TDownloadImageThreadStatus;
     FCounter     : Integer;
     FCounterAll  : Integer;
     FBasePath    : string;
     FImageFolder : string;
     FMultiThread : Boolean;
     FFirsImage   : string;
     FFirstURL    : string;
  protected
     // Protected declarations
     procedure GetMultipleItemsAPIError(Sender: TObject; ErrorRecord: eBayAPIError);
     procedure GetMultipleItemsEndRequest(Sender: TObject);
     procedure GetMultipleItemsStartRequest(Sender: TObject);
     procedure WriteEbayApiExceptionLog(E : Exception);
     procedure WriteExceptionLog(E: Exception);
     procedure SetItemsToGet(Value : TStringList);
     procedure DecTCounter;
     procedure SetGlobalID(Value : Global_ID);
     procedure EbayShoppingConnectWork(ASender: TObject; AWorkMode: TWorkMode; AWorkCount: Int64);
  public
     // Public declarations
     TID                   : Integer;
     // Objects visible outside threads
     property SiteID     : SiteCodeType read FSiteID;
     property AppID      : string read FAppID write FAppID;
     property GlobalID   : Global_ID read FGlobalID write SetGlobalID;
     property ItemsToGet : TStringList read FItemsToGet write SetItemsToGet;
     property MultiThread : Boolean read FMultiThread write FMultiThread;
     property FirstImageID : string read FFirsImage write FFirsImage;
     property FirstImageUrl : string read FFirstURL write FFirstURL;
     // methods
     constructor Create;
     destructor Destroy; override;
     procedure Run; override;
     procedure WriteToDB;
  end;

implementation

uses functions, ActiveX, IdHTTP, uMain, uHttpDownload;

{ TCompleteCheckThread }

constructor TDownloadImagesThread.Create;
begin
  inherited Create;
  FEbayShoppingConnect  := TEbayShoppingConnect.Create(nil);
  FEbayShoppingConnect.OnWork := EbayShoppingConnectWork;
  FEbayShoppingConnect.AppID := FAppID;
  FGlobalID := EBAY_US;
  FSiteID := GlobalID2SiteCode(FGlobalID);
  FEbayShoppingConnect.SiteID := FSiteID;
  FQueryItems := TnxQuery.Create(nil);
  FQueryItems.Database := fmMain.nxdtbs1;
  FQueryItems.SQL.Add('SELECT TOP 19 Items.ItemID');
  FQueryItems.SQL.Add('FROM Items');
  FQueryItems.SQL.Add('WHERE Items.PictureURL Is Null');
  FItemsToGet := TStringList.Create;
  FSyncObj := TFTSync.Create(Self);
  FBasePath := fmMain.BasePath;
  FImageFolder := 'Photos';
  DecTCounter;
  FreeOnTerminate := True;
  FMultiThread := True;
  FFirsImage := '';
end;

destructor TDownloadImagesThread.Destroy;
begin
  FreeAndNil(FEbayShoppingConnect);
  FreeAndNil(FItemsToGet);
  FreeAndNil(FSyncObj);
  FreeAndNil(FQueryItems);
  inherited;
end;

procedure TDownloadImagesThread.DecTCounter;
begin
  FSyncObj.Operation := OpDecCounter;
  FSyncObj.Synchronize;
end;

procedure TDownloadImagesThread.EbayShoppingConnectWork(ASender: TObject; AWorkMode: TWorkMode; AWorkCount: Int64);
begin
  case AWorkMode of
  wmRead  : begin
    FSyncObj.OnHttpWork(AWorkMode,AWorkCount-FRxDelta);
    FRxDelta := AWorkCount;
  end;
  wmWrite : begin
    FSyncObj.OnHttpWork(AWorkMode,AWorkCount-FTxDelta);
    FTxDelta := AWorkCount;
  end;
  end;
end;

procedure TDownloadImagesThread.GetMultipleItemsAPIError(Sender: TObject;
  ErrorRecord: eBayAPIError);
var i : Integer;
begin
  with ErrorRecord , FSyncObj do begin
    WriteAdvLog(Format('%s: ThreadID %d - ApiCall: GetMultipleItems. API Error',[DateTimeToStr(now),Self.ThreadID]));
    WriteAdvLog(Format('ShortMessage %s , LongMessage %s ',[ShortMessage, LongMessage]));
    WriteAdvLog(Format('ErrorCode %s , SeverityCode %s ,ErrorClassification, %s, index %d',[ErrorCode,SeverityCode,ErrorClassification,index]));
  end;
  FSyncObj.WriteAdvLog('Request XML');
  for i := 0 to FEbayShoppingConnect.RequestXMLText.Count -1 do FSyncObj.WriteAdvLog(FEbayShoppingConnect.RequestXMLText.Strings[i]);
  FSyncObj.WriteAdvLog('Response XML');
  for i := 0 to FEbayShoppingConnect.ResponseXMLText.Count -1 do FSyncObj.WriteAdvLog(FEbayShoppingConnect.ResponseXMLText.Strings[i]);
  FSyncObj.SaveAdvLog;
end;

procedure TDownloadImagesThread.GetMultipleItemsEndRequest(Sender: TObject);
begin
  FSyncObj.WriteLog(Format('%s: ThreadID %d - ApiCall: GetMultipleItems. Result %s',[DateTimeToStr(now),Self.ThreadID,GetEnumName(TypeInfo(AckCodeType),ord(FGetMultipleItems.Ack))]));
  FGetMultipleItems.ResponseXMLDoc.SaveToFile('GetMultipleItemsResponse.xml');
  FSyncObj.IncApiUsage;
end;

procedure TDownloadImagesThread.GetMultipleItemsStartRequest(
  Sender: TObject);
begin
  FSyncObj.WriteLog(Format('%s: ThreadID %d - ApiCall: GetMultipleItems. Starting',[DateTimeToStr(now),Self.ThreadID]));
  FGetMultipleItems.RequestXMLDoc.SaveToFile('GetMultipleItemsRequest.xml');
end;

procedure TDownloadImagesThread.Run;
var i : Integer;
    hr: HRESULT;
begin
  inherited;
  try
    hr := CoInitializeEx(nil, COINIT_APARTMENTTHREADED);
    FGetMultipleItems     := TGetMultipleItems.Create(nil);
    FGetMultipleItems.OnAPIError := GetMultipleItemsAPIError;
    FGetMultipleItems.OnStartRequest := GetMultipleItemsStartRequest;
    FGetMultipleItems.OnEndRequest := GetMultipleItemsEndRequest;
    FGetMultipleItems.Connector := FEbayShoppingConnect;
    FGetMultipleItems.IncludeSelector := [Details,ItemSpecifics,Description];
    if hr <> S_OK then Exception.Create('Error occurs: ' + IntToHex(hr, 2));
    try
      FItemsToGet.Clear;
      FItemsToGet.Add(FFirsImage);
      FQueryItems.Open;
      if FQueryItems.RecordCount >0 then begin
        while not FQueryItems.Eof do begin
          FItemsToGet.Add(FQueryItems.FieldValues['ItemID']);
          FQueryItems.Next;
        end;
        FEbayShoppingConnect.AppID := FAppID;
        FEbayShoppingConnect.SiteID := FSiteID;
        FGetMultipleItems.ItemID.Clear;
        for i := 0 to FItemsToGet.Count-1 do FGetMultipleItems.ItemID.Add(FItemsToGet.Strings[i]);
        try
          FRxDelta := 0;
          FTxDelta := 0;
          FOperationResult := FGetMultipleItems.DoRequestEx;
          if (FOperationResult in [Failure, PartialFailure]) then begin
            Exception.Create('Request Failure');
          end;
          if Terminated then Exit;
          if FOperationResult in [Success, Warning, PartialFailure] then begin
            FCounterAll := 0;
            FCounter := 0;
            WriteToDB;
            FUpdateRec.TotalItems := FCounterAll;
            FUpdateRec.SavedPhotos := FCounter;
            FSyncObj.UpdDThreadStatus(FUpdateRec);
          end;
          if (FOperationResult in [Failure, Warning, PartialFailure]) then
            with FSyncObj do begin
              WriteLog(Format('%s: ThreadID %d Request failure',[DateTimeToStr(now),Self.ThreadID]));
              WriteAdvLog('Request XML');
              for i := 0 to FEbayShoppingConnect.RequestXMLText.Count -1 do WriteAdvLog(FEbayShoppingConnect.RequestXMLText.Strings[i]);
              WriteAdvLog('Response XML');
              for i := 0 to FEbayShoppingConnect.ResponseXMLText.Count -1 do WriteAdvLog(FEbayShoppingConnect.ResponseXMLText.Strings[i]);
              SaveAdvLog;
            end;
        except
          on E : Exception do WriteEbayApiExceptionLog(E);
        end;
        if Terminated then Stop;
      end
      else Stop;
    finally
      FQueryItems.Close;
    end;
  finally
    CoUninitialize;
    FreeAndNil(FGetMultipleItems);
  end;
  Stop;
end;

procedure TDownloadImagesThread.WriteEbayApiExceptionLog(E: Exception);
var i : Integer;
begin
  with FSyncObj do begin
    WriteLog(Format('%s: ThreadID %d Exception',[DateTimeToStr(now),Self.ThreadID]));
    WriteLog(Format('Exception class name: %s',[E.ClassName]));
    WriteLog(Format('Exception message: %s',[E.Message]));
    WriteAdvLog('Request XML');
    for i := 0 to FEbayShoppingConnect.RequestXMLText.Count -1 do WriteAdvLog(FEbayShoppingConnect.RequestXMLText.Strings[i]);
    WriteAdvLog('Response XML');
    for i := 0 to FEbayShoppingConnect.ResponseXMLText.Count -1 do WriteAdvLog(FEbayShoppingConnect.ResponseXMLText.Strings[i]);
    SaveAdvLog;
  end;
end;

procedure TDownloadImagesThread.WriteExceptionLog(E: Exception);
begin
  with FSyncObj do begin
    WriteLog(Format('%s: ThreadID %d Exception',[DateTimeToStr(now),Self.ThreadID]));
    WriteLog(Format('Exception class name: %s',[E.ClassName]));
    WriteLog(Format('Exception message: %s',[E.Message]));
    SaveAdvLog;
  end;
end;

procedure TDownloadImagesThread.WriteToDB;
var i, j: Integer;
    MemStream: TMemoryStream;
    ImgHttp : TidHttp;
    ContentType : string;
    ItemDetails : TItemDetails;
begin
  try
    for i:=0 to FGetMultipleItems.Items.Count-1 do
    with FGetMultipleItems.Items.Items[i] do begin
      inc(FCounterAll);
      ItemDetails.PictureURL := No_Photo;
      ItemDetails.ItemID := ItemID;
      ItemDetails.Description := Description;
      if ChildNodes.FindNode('PictureURL') <> nil then begin
      //if PictureURL <> nil then begin
        try
          ItemDetails.PictureURL := PictureURL[0];
        except
          ItemDetails.PictureURL := No_Photo;
        end;
      end;
      // try save photo url
      if FFirsImage = ItemID then FFirstURL := ItemDetails.PictureURL;
      FSyncObj.SavePictureDetails(ItemDetails);
      inc(FCounter);
      //**************
      // end try download photos
    end;
  except
    on E : Exception do
    begin
      WriteExceptionLog(E);
      FSyncObj.WriteLog(Format('Exception ItemID: %s',[ItemDetails.ItemID]));
    end;
  end;
end;

procedure TDownloadImagesThread.SetItemsToGet(Value : TStringList);
begin
  if Value <> nil then FItemsToGet.Assign(Value);
end;

procedure TDownloadImagesThread.SetGlobalID(Value : Global_ID);
begin
  FGlobalID := Value;
  FSiteID := GlobalID2SiteCode(FGlobalID);
  FEbayShoppingConnect.SiteID := FSiteID;
end;

initialization
  Randomize;

end.
